/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package tools;

import com.openbrew.openbrewrf.Administration;
import com.openbrew.openbrewrf.POSLineItems;
import com.openbrew.openbrewrf.POSProductServingType;
import com.openbrew.openbrewrf.POSVolume;
import com.openbrew.openbrewrf.Sales;
import com.openbrew.openbrewrf.ScanTblKeg;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;

/**
 *
 * @author chapmand
 */
public class POSVolumeModifier {
    private Administration admin = null;
    
    
    /***************************************************************************
     * Function to process a Volume movement.
     * @param en Entity Manager from calling class.
     * @param lineItem Line Item containing product to be moved.
     **************************************************************************/
    public void doVolumeRemoval(final EntityManager en, final POSLineItems lineItem){
        if(!lineItem.getProduct().getGlassware().isPrePackaged()){
            if(lineItem.getProduct().getServingTypeBeer()!=null){
                final int beerID = lineItem.getProduct().getServingTypeBeer().getbId();
                POSVolume volume = getVolume(en, beerID);
                float newVolume = volume.getCurrentVolume() - (lineItem.getProduct().getGlassware().getSize()*(float)lineItem.getQty());
                if(newVolume < 0){
                    newVolume = 0;
                }
                volume.setCurrentVolume(newVolume);
                en.merge(volume);
            }
        }
    }
    
    /***************************************************************************
     * Function to process a Volume movement.
     * @param en Entity Manager from calling class.
     * @param products Array list of products to be modified.
     **************************************************************************/
    public void doVolumeRemoval(final EntityManager en, final List<POSProductServingType> products){
        for(POSProductServingType product : products){
            if(!product.getGlassware().isPrePackaged()){
                if(product.getServingTypeBeer()!=null){
                    final int beerID = product.getServingTypeBeer().getbId();
                    POSVolume volume = getVolume(en, beerID);
                    float newVolume = volume.getCurrentVolume() - (product.getGlassware().getSize());
                    if(newVolume < 0){
                        newVolume = 0;
                    }
                    volume.setCurrentVolume(newVolume);
                    en.merge(volume);
                }
            }
        }
    }
    
    /***************************************************************************
     * Function to process a volume movement based on change of quantity.
     * @param en Entity Manager from calling class.
     * @param lineItem Line Item containing product to be moved.
     * @param oldQty old quantity.
     * @param newQty new quantity.
     **************************************************************************/
    public void doVolumeChangeRemoval(final EntityManager en, final POSLineItems lineItem, final float oldQty, final float newQty){
        if(!lineItem.getProduct().getGlassware().isPrePackaged()){
            if(newQty > oldQty){
                if(lineItem.getProduct().getServingTypeBeer()!=null){
                    final int beerID = lineItem.getProduct().getServingTypeBeer().getbId();
                    final float quantityChange = newQty - oldQty;
                    POSVolume volume = getVolume(en, beerID);
                    float newVolume = volume.getCurrentVolume() - (lineItem.getProduct().getGlassware().getSize()*quantityChange);
                    if(newVolume < 0){
                        newVolume = 0;
                    }
                    volume.setCurrentVolume(newVolume);
                    en.merge(volume);
                }
            }
        }
    }
    
    /***************************************************************************
     * Function to process a keg scan into Movement.
     * @param en Entity Manager from calling class.
     * @param keg The keg that was just scanned.
     **************************************************************************/
    public void doVolumeAddition(final EntityManager en, final ScanTblKeg keg){
        loadAdmin(en);
        if(admin.isbPOS() && (keg.getKegCust().getCId() == admin.getTrCust().getCId())){
            final int beerID = keg.getKegBeer().getbId();
            final float volToAdd = convertBBLtoOz(keg.getKegPackageID().getPackageTypeVol());
            POSVolume volume = getVolume(en, beerID);
            //move volumes to appropriate locations.
            if(volume.getCurrentVolume()!=0){
                switch(volume.getLossIndex()){
                    case 0:
                        volume.setVolumeLoss0(volume.getCurrentVolume());
                        volume.setLossIndex(volume.getLossIndex()+1);
                        break;
                    case 1:
                        volume.setVolumeLoss1(volume.getCurrentVolume());
                        volume.setLossIndex(volume.getLossIndex()+1);
                        break;
                    case 2:
                        volume.setVolumeLoss2(volume.getCurrentVolume());
                        volume.setLossIndex(volume.getLossIndex()+1);
                        break;
                    case 3:
                        volume.setVolumeLoss3(volume.getCurrentVolume());
                        volume.setLossIndex(volume.getLossIndex()+1);
                        break;
                    case 4:
                        volume.setVolumeLoss4(volume.getCurrentVolume());
                        volume.setLossIndex(volume.getLossIndex()+1);
                        break;
                    case 5:
                        volume.setVolumeLoss5(volume.getCurrentVolume());
                        volume.setLossIndex(volume.getLossIndex()+1);
                        break;
                    case 6:
                        volume.setVolumeLoss6(volume.getCurrentVolume());
                        volume.setLossIndex(volume.getLossIndex()+1);
                        break;
                    case 7:
                        volume.setVolumeLoss7(volume.getCurrentVolume());
                        volume.setLossIndex(volume.getLossIndex()+1);
                        break;
                    case 8:
                        volume.setVolumeLoss8(volume.getCurrentVolume());
                        volume.setLossIndex(volume.getLossIndex()+1);
                        break;
                    case 9:
                        volume.setVolumeLoss9(volume.getCurrentVolume());
                        volume.setLossIndex(0);
                        break;
                    default:
                        volume.setVolumeLoss9(volume.getCurrentVolume());
                        volume.setLossIndex(0);
                        break;
                }
                volume.setCurrentVolume(volToAdd);

                //Since we should never ever have a zero amount left over, we need to only average non-zero values.
                float averageTen = 0;
                int averageNum = 0;
                if(volume.getVolumeLoss0()!=0){averageTen += volume.getVolumeLoss0();averageNum++;}
                if(volume.getVolumeLoss1()!=0){averageTen += volume.getVolumeLoss1();averageNum++;}
                if(volume.getVolumeLoss2()!=0){averageTen += volume.getVolumeLoss2();averageNum++;}
                if(volume.getVolumeLoss3()!=0){averageTen += volume.getVolumeLoss3();averageNum++;}
                if(volume.getVolumeLoss4()!=0){averageTen += volume.getVolumeLoss4();averageNum++;}
                if(volume.getVolumeLoss5()!=0){averageTen += volume.getVolumeLoss5();averageNum++;}
                if(volume.getVolumeLoss6()!=0){averageTen += volume.getVolumeLoss6();averageNum++;}
                if(volume.getVolumeLoss7()!=0){averageTen += volume.getVolumeLoss7();averageNum++;}
                if(volume.getVolumeLoss8()!=0){averageTen += volume.getVolumeLoss8();averageNum++;}
                if(volume.getVolumeLoss9()!=0){averageTen += volume.getVolumeLoss9();averageNum++;}
                if(averageNum != 0){
                    averageTen = averageTen / (float)averageNum;
                    if(volume.getAverageLoss()!=0){
                        volume.setAverageLoss((volume.getAverageLoss() + averageTen)/(float)2);
                    } else {
                        volume.setAverageLoss(averageTen);
                    }
                    en.merge(volume);
                }
            } else {
                volume.setCurrentVolume(volToAdd);
                en.merge(volume);
            }
        }
    }
    
    /***************************************************************************
     * Function to process a keg scan into Movement.
     * @param en Entity Manager from calling class.
     * @param sale
     **************************************************************************/
    public void doVolumeAddition(final EntityManager en, final Sales sale){
        loadAdmin(en);
        if(admin.isbPOS() && (sale.getCustID().getCId() == admin.getTrCust().getCId())){
            final int beerID = sale.getSalesFGIID().getFGIBeerID().getbId();
            final float volToAdd = convertBBLtoOz(sale.getSalesFGIID().getFGIPackageID().getPackageTypeVol());
            POSVolume volume = getVolume(en, beerID);
            //move volumes to appropriate locations.
            if(volume.getCurrentVolume()!=0){
                switch(volume.getLossIndex()){
                    case 0:
                        volume.setVolumeLoss0(volume.getCurrentVolume());
                        volume.setLossIndex(volume.getLossIndex()+1);
                        break;
                    case 1:
                        volume.setVolumeLoss1(volume.getCurrentVolume());
                        volume.setLossIndex(volume.getLossIndex()+1);
                        break;
                    case 2:
                        volume.setVolumeLoss2(volume.getCurrentVolume());
                        volume.setLossIndex(volume.getLossIndex()+1);
                        break;
                    case 3:
                        volume.setVolumeLoss3(volume.getCurrentVolume());
                        volume.setLossIndex(volume.getLossIndex()+1);
                        break;
                    case 4:
                        volume.setVolumeLoss4(volume.getCurrentVolume());
                        volume.setLossIndex(volume.getLossIndex()+1);
                        break;
                    case 5:
                        volume.setVolumeLoss5(volume.getCurrentVolume());
                        volume.setLossIndex(volume.getLossIndex()+1);
                        break;
                    case 6:
                        volume.setVolumeLoss6(volume.getCurrentVolume());
                        volume.setLossIndex(volume.getLossIndex()+1);
                        break;
                    case 7:
                        volume.setVolumeLoss7(volume.getCurrentVolume());
                        volume.setLossIndex(volume.getLossIndex()+1);
                        break;
                    case 8:
                        volume.setVolumeLoss8(volume.getCurrentVolume());
                        volume.setLossIndex(volume.getLossIndex()+1);
                        break;
                    case 9:
                        volume.setVolumeLoss9(volume.getCurrentVolume());
                        volume.setLossIndex(0);
                        break;
                    default:
                        volume.setVolumeLoss9(volume.getCurrentVolume());
                        volume.setLossIndex(0);
                        break;
                }
                volume.setCurrentVolume(volToAdd);

                //Since we should never ever have a zero amount left over, we need to only average non-zero values.
                float averageTen = 0;
                int averageNum = 0;
                if(volume.getVolumeLoss0()!=0){averageTen += volume.getVolumeLoss0();averageNum++;}
                if(volume.getVolumeLoss1()!=0){averageTen += volume.getVolumeLoss1();averageNum++;}
                if(volume.getVolumeLoss2()!=0){averageTen += volume.getVolumeLoss2();averageNum++;}
                if(volume.getVolumeLoss3()!=0){averageTen += volume.getVolumeLoss3();averageNum++;}
                if(volume.getVolumeLoss4()!=0){averageTen += volume.getVolumeLoss4();averageNum++;}
                if(volume.getVolumeLoss5()!=0){averageTen += volume.getVolumeLoss5();averageNum++;}
                if(volume.getVolumeLoss6()!=0){averageTen += volume.getVolumeLoss6();averageNum++;}
                if(volume.getVolumeLoss7()!=0){averageTen += volume.getVolumeLoss7();averageNum++;}
                if(volume.getVolumeLoss8()!=0){averageTen += volume.getVolumeLoss8();averageNum++;}
                if(volume.getVolumeLoss9()!=0){averageTen += volume.getVolumeLoss9();averageNum++;}
                if(averageNum != 0){
                    averageTen = averageTen / (float)averageNum;
                    if(volume.getAverageLoss()!=0){
                        volume.setAverageLoss((volume.getAverageLoss() + averageTen)/(float)2);
                    } else {
                        volume.setAverageLoss(averageTen);
                    }
                    en.merge(volume);
                }
            } else {
                volume.setCurrentVolume(volToAdd);
                en.merge(volume);
            }
        }
    }
    
    //Converts BBL(s) to Ounces.
    private float convertBBLtoOz(final float bbl){
        return bbl * (float)31 * (float)128;
    }
    
    //Finds the volume associated with given beer id.
    private POSVolume getVolume(final EntityManager en, final int beerID){
        TypedQuery<POSVolume> query = en.createQuery(
                "SELECT v FROM POSVolume v WHERE v.id = ?1", POSVolume.class);
        query.setParameter(1, beerID);
        List<POSVolume> vols = query.getResultList();
        if(vols.size()>0){
            return vols.get(0);
        }
        //No volume found, we need to insert a new volume.
        return insertNewVolume(en, beerID);
    }
        
    //Loads admin from database.
    private void loadAdmin(EntityManager en){
        admin = en.createNamedQuery("Administration.findAll", Administration.class).getResultList().get(0);
    }
    
    //creates and inserts new volume, then returns that new volume to computer.
    private POSVolume insertNewVolume(final EntityManager en, final int beerID){
        POSVolume newVolume = new POSVolume();
        newVolume.setId(beerID);
        newVolume.setAverageLoss(0);
        newVolume.setCurrentVolume(0);
        newVolume.setLossIndex(0);
        newVolume.setVolumeLoss0(0);
        newVolume.setVolumeLoss1(0);
        newVolume.setVolumeLoss2(0);
        newVolume.setVolumeLoss3(0);
        newVolume.setVolumeLoss4(0);
        newVolume.setVolumeLoss5(0);
        newVolume.setVolumeLoss6(0);
        newVolume.setVolumeLoss7(0);
        newVolume.setVolumeLoss8(0);
        newVolume.setVolumeLoss9(0);
        en.persist(newVolume);
        return newVolume;
    }
}
